package cn.tedu.spring.day02am;

import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Spring 框架    IOC控制反转内容
 */
public class SpringDemoTest {
    /**
     * （重点）SpringIOC编写流程
     *
     */
    @Test
    public void test01(){
    //1.创建Spring容器   ApplicationContext(抽象类：不能直接实例化)--配置文件：获取类  加载bean
        ApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");
    //2.获取对象 getBean()
        Tom tom=(Tom)ac.getBean("tom");
        tom.say();
     //3.关闭Spring容器
        ((ClassPathXmlApplicationContext)ac).close();
    }
    /**
     * Spring ---IOC流程问题：
     * 1.默认情况下，多次获取到同一个id的bean，得到的是“同一个对象”
     * 2."不可以"配置多个id相同的bean
     *  Spring容器内置Map id理解key 键不允许重复
     * 3.配置多个id不同，但class相同的bean
     *
     */
    /**
     * getBean()获取对象问题：获取类的对象
     */
    @Test
    public void test02(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");

        //获取类信息问题:①使用id获取  ②获取class  类.class
        Tom tom=ac.getBean(Tom.class);
        tom.say();

        ((ClassPathXmlApplicationContext)ac).close();
    }
    /**
     *  Spring IOC 流程问题：
     *  4.Spring默认调用无参数构造器（✔）
     *  5.Spring调用有参数构造器
     */
    @Test
    public void test03(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");
        Tom tom=(Tom)ac.getBean("toms");
        System.out.println(tom);
    }
    /**
     * SpringIOC 流程问题
     * 6.支持工厂设计模式：静态工厂、实例工厂、Spring工厂（java23种设计模式）
     * 静态工厂：设计模式【固定结构】
     * Spring IOC控制反转---支持静态工厂
     *
     */
    @Test
    public void test04(){
        //问题1   静态工厂  xml编写 factory-method="静态方法名"
        ApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");
       //问题2   获取对象   NetConnection:执行功能类   NetConnectionFactory: 提供功能：静态方法“链接三个输出语句”
       NetConnection nc=(NetConnection) ac.getBean("ncf");    //从静态工厂调用3个方法
       //ac.getBean("ncf"); ===NetConnectionFactory.getInstance();
        nc.sendData(); //发送数据
        //关闭
        ((ClassPathXmlApplicationContext)ac).close();
    }
    /**
     *  SpringIOC控制反转 支持 工厂模式：实例工厂
     *  如何从实例工厂获取到对象
     */
    @Test
    public void test05(){
        //配置文件
        ApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml");
        //实例工厂---如何获取NetConnection 四个方法
        // 获取  NetConnection  NetConnectionInstance[实例工厂：提供3个方法]
        NetConnection nc=(NetConnection) ac.getBean("nc");
        nc.sendData();
        //关闭 ioc容器
        ((ClassPathXmlApplicationContext)ac).close();
    }

    /**
     * Spring   提供Spring工厂(优选)
     *   创建Spring工厂类
     *   实现接口  FactoryBean
     */
    @Test
    public void test06(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
        //从Spring工厂对象中获取到网络链接类【NetConnection】
        NetConnection ncsf=(NetConnection) ac.getBean("ncsf");
        ncsf.sendData();
    }







    /**
     * 单例模式：
     * SpringIOC执行默认单例模式，容器初始化创建对象时候，通过反射将对象保存在容器Map键[key]中，
     * 之后从Map中找到对应键获取对应bean（对象）！
     * 总结：Spring内置Map【集合】--key【不重复】--value
     *
     * 多例模式：
     * SpringIOC执行不支持，需要指定模式多例，出现特定业务需求
     * 容器初始化不创建对象，而是获取bean时，创建对象并且返回！不会从容器内部获取对象，每次得到新对象
     *
     * 模拟业务： B2C 电商类 --->购物车---->来N用户【购物车添加商品】--->付款
     *                              ---->1用户-----付款
     *                              ---->2用户-----付款
     *
     *  scope属性---xxx.xml配置文件
     *  1.创建Person类
     *  2.SpringIoc流程
     *  【Spring默认单例】
     */
    @Test
    public  void  test07(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
        Person p1=(Person)ac.getBean("person");  //第一次创建对象--将对象存Map 键
        p1.doing();
        Person p2=(Person)ac.getBean("person");  //第二次--取Map键--对象取出
        p2.doing();
        ((ClassPathXmlApplicationContext)ac).close();
        //String 常量池：
    }

    /**Spring默认执行单例模式：节省内存，操作手法:从Spring容器Map键获取对象。不需要每次创建新对象
     * 如果bean【创建对象】多了，需要优先原则
     *
     * 懒加载  bean.xml---<bean lazy-init="true"><bean/>
     *
     */
      @Test
    public void test08(){
    ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
    Person p1=(Person)ac.getBean("person3");  //person3设置懒加载：true
    System.out.println(p1);
    Person p2=(Person)ac.getBean("person3");  //person3设置懒加载：true
     System.out.println(p2);
     ((ClassPathXmlApplicationContext)ac).close();
      }




}
